package ldh.im.fxbase.component;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.*;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.robot.Robot;
import javafx.scene.shape.*;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.stage.*;
import javafx.util.Duration;
import ldh.im.ImConfig;
import ldh.im.fxbase.controller.CaptureControlController;
import ldh.im.fxbase.util.RegionUtil;
import ldh.im.fxbase.util.RpcUtil;
import ldh.im.fxbase.data.vo.CanvasItem;
import ldh.im.fxbase.data.vo.CanvasPoint;
import ldh.im.util.ConfigUtil;
import ldh.im.util.RandomCharacterUtil;
import ldh.rpc.cache.CacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * 代码重构： 将背景图从ImageView改成Canvas
 */
public class ScreenCapturePane extends AnchorPane {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScreenCapturePane.class);

    private volatile Stage parentStage = null;
    private Stage captureStage = null;

    private Scene scene = null;
    private Rectangle rectangle = new Rectangle();
    private List<Rectangle> dragRectangles = new ArrayList<>();  // 移动小手柄
    private MaskPane maskPane = new MaskPane();
    private Label positionLabel = new Label();
    private Label tip = new Label("开始截屏");
    private RegionUtil.FxmlBean<HBox, CaptureControlController> fxmlBean;
    private StackPane controlPane = new StackPane();
    private Canvas canvas = new Canvas();
    private GraphicsContext graphicsContext = canvas.getGraphicsContext2D();
    private Point2D origin = null;
    private Screen screen = null;
    private Robot robot = new Robot();
    private ImageView fullScreenImageView = new ImageView();
    private boolean canCapture = true;
    private List<CanvasItem> canvasItems = new ArrayList<>();
    private Image captureImage;
    private CanvasItem currentCanvasItem;
    private Point2D currentCanvasPoint = null;
    private Point2D originCanvasPoint = null;
    private TextField textField = new TextField();
    private boolean canvasItemChangePosition = false;  // cavas上的元素调整位置
    private Consumer<String> captureConsumer;
    private String imageCacheDir = ConfigUtil.getRoot() + "/capture";//"F:\\tmp\\capture";
    private DirectoryChooser directoryChooser = new DirectoryChooser();

    public ScreenCapturePane() {
//        this.webView = webView;
        screen = Screen.getPrimary(); //getScreen(webView);
        this.setStyle("-fx-background-color: rgb(0,0,0,0.01)");

        rectangle.setFill(Color.TRANSPARENT);
        rectangle.setStroke(Color.GREEN);

        controlPane.setStyle("-fx-background-color: derive(lightgrey, 30%)");

        maskPane.setOpacity(0.4);

        tip.setStyle("-fx-text-fill: yellow; -fx-font-size: 30px; ");
        tip.setLayoutX((screen.getBounds().getWidth()-100)/2);
        tip.setLayoutY(100);

        textField.setOnAction(e->{
            if (textField.isVisible() && currentCanvasItem != null && currentCanvasItem.getType() == 3) {
                textField.setVisible(false);
                currentCanvasItem.setText(textField.getText());
                draw();
                canvasItemChangePosition = true;
            };
        });
//        this.getChildren().addAll(fullScreenImageView, tip, rectangle, maskRectangle, positionLabel, canvas, controlPane, textField); // , position, canvas, controlPane
        this.getChildren().addAll(fullScreenImageView, tip, rectangle); // , position, canvas, controlPane
        initDragRectangles();
        this.getChildren().addAll(maskPane, positionLabel, canvas, controlPane, textField); // , position, canvas, controlPane

        initPopup();

        initBind();
        initEvent();
    }

    public void stopCapture() {
        this.canCapture = false;
    }

    public void setCanvasType(Color color, int type) {
        currentCanvasItem = new CanvasItem(0, 0, 0, 0, color, type);
        if (type == 4) currentCanvasItem.setColor(Color.LIGHTGRAY);
        canvasItemChangePosition = false;
    }

    public void undoCanvas() {
        if(canvasItems.size() < 1) return;
        canvasItems.remove(canvasItems.size()-1);
        draw();
    }

    public void setParentStage(Stage stage) {
        this.parentStage = stage;

        captureStage = new Stage();
        captureStage.setMaximized(true);

        captureStage.setScene(scene);
        captureStage.initStyle(StageStyle.TRANSPARENT);
        captureStage.initModality(Modality.APPLICATION_MODAL);
        captureStage.initOwner(parentStage);
    }

    private void initPopup() {
        fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource("/ldh/im/fxbase/fxmls/CaptureControlPane.fxml"));
        fxmlBean.getController().setScreenCapturePane(this);
        controlPane.getChildren().add(fxmlBean.getNode());

        scene = new Scene(this);
        scene.setFill(Color.TRANSPARENT);
    }

    public void show(Consumer<String> captureConsumer) {
        show(captureConsumer, true);
    }

    public void show(Consumer<String> captureConsumer, boolean isHideStage) {
        this.captureConsumer= captureConsumer;

        tip.setVisible(true);
        positionLabel.setFont(Font.font(Font.getDefault().getFamily(), 22));
        positionLabel.setVisible(false);
        controlPane.setVisible(false);
        maskPane.setVisible(false);
//        canvas.setVisible(false);
        captureImage = null;
        canvasItems.clear();
        canCapture = true;
        textField.setText("");
        textField.setVisible(false);
        canvasItemChangePosition = false;

//        ThreadPoolUtil.schedule(()->Platform.runLater(()->tip.setVisible(false)), 2000);
        rectangle.setWidth(0);
        rectangle.setHeight(0);
        dragRectangles.forEach(e->e.setVisible(false));
//        popup.show(webView.getScene().getWindow(), 0d, 0d);

        if (isHideStage) {
            parentStage.setIconified(true);
        }
//        StageUtil.getStage().hide();
        captureFullScreen();

        captureStage.show();

        playTipAnination();
    }

    public void callbackForCapture(String capture) {
        captureConsumer.accept(capture);
    }

    public void hide() {
        controlPane.setVisible(false);
//        popup.hide();
        captureStage.close();
//        StageUtil.getStage().show();
        parentStage.setIconified(false);
//        StageUtil.getStage().getScene().getRoot().setVisible(false);
    }

    public String getCaptureImageUrl() {
//        Image image = canvas.snapshot(new SnapshotParameters(), null);
        CacheService cacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getCacheService();
        String userId = (String) cacheService.getCache(ImConfig.LOGIN_USER_ID);
        userId = userId == null ? "tmp" : userId;
        String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String dir = imageCacheDir + File.separator + userId + File.separator + dateStr;
        File imageCacheFile = new File(dir);
        if (!imageCacheFile.exists()) {
            imageCacheFile.mkdirs();
        }

        String file = dir + File.separator + System.currentTimeMillis() + RandomCharacterUtil.getRandomCharacter(5) + ".png";
        File imageFile = new File(file);
        saveImage(captureImage, imageFile);
//        String captureImageUrl = imageFile.getAbsolutePath().replace("\\", "/");
        return file;
    }

    private void saveImage(Image image, File imageFile) {
        BufferedImage bImage = SwingFXUtils.fromFXImage(image, null);
        try {
            ImageIO.write(bImage, "png", imageFile);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void captureFullScreen() {
        double w = screen.getBounds().getWidth();
        double h = screen.getBounds().getHeight();
        WritableImage writableImage = captureScreen(0, 0, w, h, false);
        fullScreenImageView.setFitWidth(w);
        fullScreenImageView.setFitHeight(h);
        LOGGER.info(String.format("image size: %s， %s; screen size: %s, %s", writableImage.getWidth(), writableImage.getHeight(), w, h));
        fullScreenImageView.setImage(writableImage);
    }

    public void captureRectangleScreen() {
        if (rectangle.getHeight() < 1 || rectangle.getWidth() < 1) return;
        WritableImage writableImage = captureScreen(rectangle.getX()+1, rectangle.getY()+1, rectangle.getWidth()-2, rectangle.getHeight()-2, false); // -12
        captureImage = writableImage;
        LOGGER.info(String.format("image size: %s， %s; screen size: %s, %s", writableImage.getWidth(), writableImage.getHeight(), rectangle.getWidth()-2, rectangle.getHeight()-2));
        System.setProperty("prism.allowhidpi", "1.5");
    }

    public void saveCapturePicture() {
        directoryChooser.setTitle("选择文件夹");
        File dir = directoryChooser.showDialog(parentStage.getOwner());
        if (dir == null) return;
        String file = dir + File.separator + System.currentTimeMillis() + ".png";
        File imageFile = new File(file);
        saveImage(captureImage, imageFile);
    }

    private void initEvent() {
        this.setOnMousePressed(e->{
            if(!canCapture) return;
            positionLabel.setVisible(true);
            controlPane.setVisible(false);
            maskPane.setVisible(true);
            origin = new Point2D(e.getScreenX(), e.getScreenY());
            rectangle.setWidth(0);
            rectangle.setHeight(0);
            rectangle.setX(origin.getX());
            rectangle.setY(origin.getY());
            calcPosition();
        });

        this.setOnMouseDragged(e->{
            if(!canCapture) return;

            double nx = e.getScreenX();
            double ny = e.getScreenY();

            rectangle.setWidth((int)Math.abs(nx-origin.getX()));
            rectangle.setHeight((int)Math.abs(ny-origin.getY()));

            if (nx >= origin.getX() && e.getScreenY() >= origin.getY()) {
                rectangle.setX(origin.getX());
                rectangle.setY(origin.getY());
            } else if (nx >= origin.getX() && ny < origin.getY()) {
                rectangle.setX(origin.getX());
                rectangle.setY(ny);
            } else if (nx < origin.getX() && ny >= origin.getY()) {
                rectangle.setX(nx);
                rectangle.setY(origin.getY());
            } else {
                rectangle.setX(nx);
                rectangle.setY(ny);
            }
            rectangle.setX((int)rectangle.getX());
            rectangle.setY((int)rectangle.getY());
            calcPosition();
        });
        this.setOnMouseReleased(e->{
            if(!canCapture) return;
            if (canvas.getWidth() < 5 && canvas.getHeight() < 5) return;

            rectangle.setWidth((int)Math.abs(e.getScreenX()-origin.getX()));
            rectangle.setHeight((int)Math.abs(e.getScreenY()-origin.getY()));
            calcControlPanePosition();
        });

        this.getScene().setOnKeyPressed(e->{
            if (e.getCode() == KeyCode.LEFT) {
                moveCaptureRectangleX(-1);
                moveCaptureRectangleWidth(-1);
                moveRectangle();
            } else if (e.getCode() == KeyCode.RIGHT) {
                moveCaptureRectangleX(1);
                moveCaptureRectangleWidth(1);
                moveRectangle();
            } else if (e.getCode() == KeyCode.UP) {
                moveCaptureRectangleY(-1);
                moveCaptureRectangleHeight(-1);
                moveRectangle();
            } else if (e.getCode() == KeyCode.DOWN) {
                moveCaptureRectangleY(1);
                moveCaptureRectangleHeight(1);
                moveRectangle();
            } else if (e.getCode() == KeyCode.ESCAPE) {
                this.hide();
                captureStage.close();
            }
        });
        this.getScene().setOnKeyReleased(e->{
            if (canCapture) {
                calcPosition();
                controlPane.setVisible(true);
                rectangle.requestFocus();
                calcControlPanePosition();
            }
        });

        this.canvas.setOnMousePressed(e->{
            if(canCapture) return;
            currentCanvasPoint = new Point2D(e.getScreenX(), e.getScreenY());
            originCanvasPoint = new Point2D(currentCanvasItem.getX(), currentCanvasItem.getY());
            if(canvasItemChangePosition) return;
            if (currentCanvasItem.getType() == 2 || currentCanvasItem.getType() == 4) {
                List<CanvasPoint> canvasPoints = new ArrayList<>();
                currentCanvasItem.setCanvasPointList(canvasPoints);

                currentCanvasItem.setX(e.getScreenX());
                currentCanvasItem.setY(e.getScreenY());
            } else if (currentCanvasItem.getType() == 3) { // 输入文字
                textField.setVisible(true);
                textField.setText("");
                textField.setLayoutX(e.getScreenX());
                textField.setLayoutY(e.getScreenY());
                currentCanvasItem.setX(e.getScreenX());
                currentCanvasItem.setY(e.getScreenY());
                textField.requestFocus();
            }
            this.canvasItems.add(currentCanvasItem);
        });

        this.canvas.setOnMouseDragged(e->{
            if(canCapture) return;
            if (canvasItemChangePosition) {
                if (currentCanvasItem.getType() == 2 || currentCanvasItem.getType() == 4) {
                   return;
                }
                double cx = e.getScreenX() - currentCanvasPoint.getX();
                double cy = e.getScreenY() - currentCanvasPoint.getY();
                currentCanvasItem.setX(originCanvasPoint.getX() + cx);
                currentCanvasItem.setY(originCanvasPoint.getY() + cy);
                draw();
                return;
            }

            if (currentCanvasItem.getType() == 2 || currentCanvasItem.getType() == 4) {
                currentCanvasItem.getCanvasPointList().add(new CanvasPoint(e.getScreenX(), e.getScreenY()));
                draw();
                return;
            }

            currentCanvasItem.setWidth(Math.round(Math.abs(e.getScreenX()-currentCanvasPoint.getX())));
            currentCanvasItem.setHeight(Math.round(Math.abs(e.getScreenY()-currentCanvasPoint.getY())));
            if (e.getScreenX() >= currentCanvasPoint.getX() && e.getScreenY() >= currentCanvasPoint.getY()) {
                currentCanvasItem.setX(currentCanvasPoint.getX());
                currentCanvasItem.setY(currentCanvasPoint.getY());
            } else if (e.getScreenX() >= currentCanvasPoint.getX() && e.getScreenY() < currentCanvasPoint.getY()) {
                currentCanvasItem.setX(e.getScreenX());
                currentCanvasItem.setY(currentCanvasPoint.getY());
            } else if (e.getScreenX() < currentCanvasPoint.getX() && e.getScreenY() >= currentCanvasPoint.getY()) {
                currentCanvasItem.setX(currentCanvasPoint.getX());
                currentCanvasItem.setY(e.getScreenY());
            } else {
                currentCanvasItem.setX(e.getScreenX());
                currentCanvasItem.setY(e.getScreenY());
            }
            draw();
        });

        this.canvas.setOnMouseReleased(e->{
            if(canCapture) return;
            if (currentCanvasItem.getType() == 2 || currentCanvasItem.getType() == 4) {
                  setCanvasType(currentCanvasItem.getColor(), currentCanvasItem.getType());
                  return;
            }
            canvasItemChangePosition = true;
        });
    }

    private void moveRectangle() {
        rectangle.requestFocus();
        controlPane.setVisible(false);
        calcPosition();
        dragRectangles();
    }

    private void initBind() {
        canvas.widthProperty().bind(rectangle.widthProperty());
        canvas.heightProperty().bind(rectangle.heightProperty());
        rectangle.xProperty().addListener((InvalidationListener)l->canvas.setLayoutX(rectangle.getX()));
        rectangle.yProperty().addListener((InvalidationListener)l->canvas.setLayoutY(rectangle.getY()));

        canvas.widthProperty().addListener((InvalidationListener)l->dragRectangles());
        canvas.heightProperty().addListener((InvalidationListener)l->dragRectangles());

        maskPane.xProperty().bind(rectangle.xProperty());
        maskPane.yProperty().bind(rectangle.yProperty());

        maskPane.hProperty().bind(rectangle.heightProperty());
        maskPane.wProperty().bind(rectangle.widthProperty());
    }

    private void draw() {
        graphicsContext.clearRect(0, 0, rectangle.getWidth(), rectangle.getHeight());
        graphicsContext.setFill(Color.LIGHTGRAY);
        canvasItems.forEach(canvasItem -> {
            if (canvasItem.getType() == 0) {
                graphicsContext.setStroke(canvasItem.getColor());
                graphicsContext.setLineWidth(2);
                graphicsContext.strokeRect(canvasItem.getX()-rectangle.getX(), canvasItem.getY()-rectangle.getY(), canvasItem.getWidth(), canvasItem.getHeight()); // +14
            } else if (canvasItem.getType() == 1) {
                graphicsContext.setStroke(canvasItem.getColor());
                graphicsContext.setLineWidth(2);
                graphicsContext.strokeOval(canvasItem.getX()-rectangle.getX(), canvasItem.getY()-rectangle.getY(), canvasItem.getWidth(), canvasItem.getHeight()); // +14
            } else if (canvasItem.getType() == 2 || canvasItem.getType() == 4) {  // 2 随便划线; 4 擦除数据
                if(canvasItem.getCanvasPointList().size() <1) return;
                graphicsContext.setFill(canvasItem.getColor());
                graphicsContext.setStroke(canvasItem.getColor());
                graphicsContext.setLineWidth(2);
                if(canvasItem.getType() == 4) {
                    graphicsContext.setLineCap(StrokeLineCap.ROUND);
                    graphicsContext.setLineWidth(10);
                }
                graphicsContext.beginPath();

                graphicsContext.moveTo(canvasItem.getX()-rectangle.getX(), canvasItem.getY()-rectangle.getY()); // +14
                for(CanvasPoint cp : canvasItem.getCanvasPointList()) {
                    graphicsContext.lineTo(cp.getX()-rectangle.getX(), cp.getY()-rectangle.getY()); // +14
                }
                graphicsContext.stroke();
            } else if (canvasItem.getType() == 3) {  // 文字
                graphicsContext.setFill(canvasItem.getColor());
                graphicsContext.setStroke(canvasItem.getColor());
                graphicsContext.fillText(canvasItem.getText(), canvasItem.getX()-rectangle.getX(), canvasItem.getY()-rectangle.getY()+18); // +14
            }
        });
    }

    // 计算截图尺寸大小的位置
    private void calcPosition() {
        int w = (int)(rectangle.getWidth()-2);
        int h = (int)(rectangle.getHeight()-2);
        w = w < 0 ? 0 : w;
        h = h < 0 ? 0 : h;
        String text = String.format("X:%s, Y:%s, 宽度:%s, 高度:%s", (int)rectangle.getX(), (int)rectangle.getY(), w, h);
        if (rectangle.getY() > 30) {
            positionLabel.setStyle("-fx-text-fill: #f5fffa");
            positionLabel.setLayoutX(rectangle.getX());
            positionLabel.setLayoutY(rectangle.getY() - 30);
            positionLabel.setText(text);
        } else {
            positionLabel.setStyle("-fx-text-fill: #f5fffa");
            positionLabel.setLayoutX(rectangle.getX());
            positionLabel.setLayoutY(rectangle.getY() + 10);
            positionLabel.setText(text);
        }
    }

    // 计算图片控制面板的位置
    private void calcControlPanePosition() {
        controlPane.setVisible(true);
        int cap = 10;
        double x = rectangle.getX() + rectangle.getWidth() - controlPane.getWidth();
        double y = rectangle.getY() + rectangle.getHeight() + cap/2;

        x = x < 0 ? rectangle.getX() : x;
        if (y + controlPane.getHeight() + cap/2 > screen.getBounds().getHeight()) {
            if (rectangle.getY() - controlPane.getHeight() - cap/2 <= 0) {
                y = y - controlPane.getHeight() - cap/2;
            } else {
                y = rectangle.getY() - controlPane.getHeight() - cap/2;
            }
        }
        controlPane.setLayoutX(x);
        controlPane.setLayoutY(y);
        rectangle.requestFocus();
    }

    private Screen getScreen(Node node) {
        List<Screen> screenList = Screen.getScreens();
        for(Screen screen : screenList) {
            if (screen.getBounds().contains(node.localToScene(0, 0))) {
                return screen;
            }
        }
        throw new RuntimeException("get Screen Error!!");
    }

    private WritableImage captureScreen(double x, double y, double w, double h, boolean scaleToFit) {
        return robot.getScreenCapture(null, x, y, w, h, scaleToFit);
    }

    private void initDragRectangles() {
        for(int i=0; i<8; i++) {
            Rectangle rectangle = new Rectangle(4, 4);
            rectangle.setFill(Color.GREEN);
            this.getChildren().add(rectangle);
            dragRectangles.add(rectangle);
        }
        initDragEvent();
    }

    private void initDragEvent() {
        for(int i=0; i<8; i++) {
            Rectangle rectangle = dragRectangles.get(i);
        }
    }

    private void dragRectangles() {
        dragRectangles.forEach(e->e.setVisible(false));
        if (canvas.getWidth() > 6) {
            Rectangle rectangle = dragRectangles.get(0); // 左上角
            rectangle.setLayoutX(canvas.getLayoutX()-2);
            rectangle.setLayoutY(canvas.getLayoutY()-2);
            rectangle.setVisible(true);
        }
        if (canvas.getWidth() > 8) {
            Rectangle rectangle = dragRectangles.get(1); // 右上角
            rectangle.setLayoutX(canvas.getLayoutX() + canvas.getWidth() -2);
            rectangle.setLayoutY(canvas.getLayoutY()-2);
            rectangle.setVisible(true);
        }
        if (canvas.getWidth() > 12) {
            Rectangle rectangle = dragRectangles.get(2); // 上中
            rectangle.setLayoutX(canvas.getLayoutX() + canvas.getWidth()/2 - 2);
            rectangle.setLayoutY(canvas.getLayoutY() -2);
            rectangle.setVisible(true);
        }
        if (canvas.getHeight() > 6) {
            Rectangle rectangle = dragRectangles.get(3); // 左下角
            rectangle.setLayoutX(canvas.getLayoutX()-2);
            rectangle.setLayoutY(canvas.getLayoutY() + canvas.getHeight() -2);
            rectangle.setVisible(true);
        }
        if (canvas.getHeight() > 8 && canvas.getWidth() > 8) {
            Rectangle rectangle = dragRectangles.get(4); // 右下角
            rectangle.setLayoutX(canvas.getLayoutX() + canvas.getWidth() -2);
            rectangle.setLayoutY(canvas.getLayoutY() + canvas.getHeight() -2);
            rectangle.setVisible(true);
        }
        if (canvas.getHeight() > 12 && canvas.getWidth() > 12) {
            Rectangle rectangle = dragRectangles.get(5); // 下中
            rectangle.setLayoutX(canvas.getLayoutX() + canvas.getWidth()/2-2);
            rectangle.setLayoutY(canvas.getLayoutY() + canvas.getHeight()-2);
            rectangle.setVisible(true);
        }

        if (canvas.getHeight() > 6) {
            Rectangle rectangle = dragRectangles.get(6); // 左中
            rectangle.setLayoutX(canvas.getLayoutX()-2);
            rectangle.setLayoutY(canvas.getLayoutY() + canvas.getHeight()/2-2);
            rectangle.setVisible(true);
        }
        if (canvas.getHeight() > 8) {
            Rectangle rectangle = dragRectangles.get(7); // 右中
            rectangle.setLayoutX(canvas.getLayoutX() + canvas.getWidth()-2);
            rectangle.setLayoutY(canvas.getLayoutY()+ canvas.getHeight()/2-2);
            rectangle.setVisible(true);
        }
    }

    private boolean moveCaptureRectangleX(int x) {
        boolean movable = true;
        double nx = rectangle.getX() + x;
        nx = nx > 0 ? nx : 0;
        movable = nx != 0;
        if (nx + rectangle.getWidth() >= screen.getBounds().getWidth()) {
            nx = screen.getBounds().getWidth() - rectangle.getWidth();
            movable = false;
        }
        rectangle.setX(nx);

        if (Double.compare(rectangle.getWidth(), 0.0) == 0) {
            origin = origin.add(new Point2D(x, 0));
        }
        return movable;
    }

    private boolean moveCaptureRectangleY(int x) {
        boolean movable = true;
        double nx = rectangle.getY() + x;
        nx = nx > 0 ? nx : 0;
        movable = nx != 0;
        if (nx + rectangle.getHeight() >= screen.getBounds().getHeight()) {
            nx = screen.getBounds().getHeight() - rectangle.getHeight();
            movable = false;
        }
        rectangle.setY(nx);
        if (Double.compare(rectangle.getHeight(), 0.0) == 0) {
            origin = origin.add(new Point2D(0, x));
        }
        return movable;
    }

    private void moveCaptureRectangleWidth(int n) {
        if(rectangle.getWidth() <= 0.0) return;
        if (rectangle.getX() + rectangle.getWidth() + n > screen.getBounds().getWidth()) return;
        if (rectangle.getWidth() + n <= 0) return;
        rectangle.setWidth(rectangle.getWidth() + n);
    }

    private void moveCaptureRectangleHeight(int n) {
        if(rectangle.getHeight() <= 0.0) return;
        if (rectangle.getY() + rectangle.getHeight() + n > screen.getBounds().getHeight()) return;
        if (rectangle.getHeight() + n <= 0) return;
        rectangle.setHeight(rectangle.getHeight() + n);
    }

    private void playTipAnination() {
        Timeline timeline = new Timeline();
        timeline.getKeyFrames().add(new KeyFrame(new Duration(0), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(300), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(500), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(700), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(900), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1100), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1300), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1500), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1700), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(1900), new KeyValue(tip.textFillProperty(), Color.RED)));
        timeline.getKeyFrames().add(new KeyFrame(new Duration(2000), new KeyValue(tip.textFillProperty(), Color.YELLOW)));
        timeline.setOnFinished((e)-> tip.setVisible(false));
        timeline.playFromStart();
    }
}
